/*
 * Copyright 2011 Dominik Pretzsch <dominik.pretzsch at gmail.com>.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package de.blacksheep.jmoteextract;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.SplashScreen;
import java.awt.geom.Rectangle2D;
import de.blacksheep.jmoteextract.archive.ArchiveManager;
import de.blacksheep.jmoteextract.mvc.model.JobTableModel;
import de.blacksheep.jmoteextract.configuration.Configuration;
import de.blacksheep.jmoteextract.extraction.ExtractionQueueManager;
import de.blacksheep.jmoteextract.mvc.controller.MainController;
import de.blacksheep.jmoteextract.mvc.model.MainModel;
import de.blacksheep.jmoteextract.mvc.view.MainView;
import de.blacksheep.jmoteextract.remote.RemoteServer;
import de.blacksheep.jmoteextract.security.SecurityManagerImpl;
import de.blacksheep.jmoteextract.thread.ThreadDispatcher;
import java.io.IOException;
import java.io.InputStream;
import java.util.logging.Level;
import java.util.logging.LogManager;
import java.util.logging.Logger;
import org.jdesktop.application.Application;
import org.jdesktop.application.SingleFrameApplication;

/**
 * The main class of the application.
 */
public class JMoteExtractApp extends SingleFrameApplication {
    
    private static SplashScreen splashScreen;
    private static Rectangle2D  splashTextArea;
    private static Rectangle2D  splashProgressArea;
    private static Graphics2D   splashGraphics;
    
    // <editor-fold defaultstate="collapsed" desc="SplashScreen Handling">
    /**
     * Prepare the global variables for the other splash functions
     */
    private void splashInit()
    {
        splashScreen = SplashScreen.getSplashScreen();
        if (splashScreen != null)
        {   // if there are any problems displaying the splash this will be null
            Dimension ssDim = splashScreen.getSize();
            int height = ssDim.height;
            int width = ssDim.width;
            
            // stake out some area for our status information
            // x, y, width, height
            //splashTextArea = new Rectangle2D.Double(15., height*0.88, width * .45, 32.);
            //splashProgressArea = new Rectangle2D.Double(width * .55, height*.92, width*.4, 12 );
            splashTextArea = new Rectangle2D.Double(15., height - 41., width - 30., 15.);
            splashProgressArea = new Rectangle2D.Double(15., height - 25., width - 30., 15.);

            // create the Graphics environment for drawing status info
            splashGraphics = splashScreen.createGraphics();
            Font font = new Font("Dialog", Font.PLAIN, 11);
            splashGraphics.setFont(font);
            
            // initialize the status info
            splashText("Starting...");
            splashProgress(0);
        }
    }
    
    /**
     * Display text in status area of Splash.  Note: no validation it will fit.
     * @param str - text to be displayed
     */
    public static void splashText(String str)
    {
        if (splashScreen != null && splashScreen.isVisible())
        {   // important to check here so no other methods need to know if there
            // really is a Splash being displayed
            
            Color foreground = new Color(179,0,0);
            Color background = new Color(238,198,198);

            // erase the last status text
            splashGraphics.setPaint(background);
            splashGraphics.fill(splashTextArea);

            // draw the text
            splashGraphics.setPaint(foreground);
            splashGraphics.drawString(str, (int)(splashTextArea.getX() + 10),(int)(splashTextArea.getY() + 12));

            // make sure it's displayed
            splashScreen.update();
        }
    }
    
    /**
     * Display a (very) basic progress bar
     * @param pct how much of the progress bar to display 0-100
     */
    public static void splashProgress(int pct)
    {
        if (splashScreen != null && splashScreen.isVisible())
        {
            Color foreground = new Color(179,0,0);
            Color background = new Color(238,198,198);

            // Note: 3 colors are used here to demonstrate steps
            // erase the old one
            splashGraphics.setPaint(background);
            splashGraphics.fill(splashProgressArea);

            // draw an outline
            splashGraphics.setPaint(foreground);
            splashGraphics.draw(splashProgressArea);

            // Calculate the width corresponding to the correct percentage
            int x   = (int) splashProgressArea.getMinX();
            int y   = (int) splashProgressArea.getMinY();
            int wid = (int) splashProgressArea.getWidth();
            int hgt = (int) splashProgressArea.getHeight();

            int doneWidth = Math.round(pct*wid/100.f);
            doneWidth = Math.max(0, Math.min(doneWidth, wid-1));  // limit 0-width

            // fill the foreground part one pixel smaller than the outline
            splashGraphics.setPaint(foreground);
            splashGraphics.fillRect(x+1, y+1, doneWidth, hgt-1);

            // make sure it's displayed
            splashScreen.update();
        }
    }
    // </editor-fold>

    /**
     * At startup create and show the main frame of the application.
     */
    @Override
    protected void startup() {                
        try {
            String logPropFile = "de/blacksheep/jmoteextract/configuration/log.properties";
            InputStream logPropStream = getClass().getClassLoader().getResourceAsStream(logPropFile);
            LogManager.getLogManager().readConfiguration(logPropStream);
        } catch (IOException ex) {
            Logger.getLogger(JMoteExtractApp.class.getName()).log(Level.SEVERE, null, ex);
        } catch (SecurityException ex) {
            Logger.getLogger(JMoteExtractApp.class.getName()).log(Level.SEVERE, null, ex);
        }
        
        splashInit();        
        splashText("Setup Security Manager...");
        
        if (System.getSecurityManager() == null) {
            Configuration config = Configuration.getInstance();
            String policyFilePath = config.getProperty(Configuration.PROP.SECURITY, "policyFile");
            
            ClassLoader cl = getClass().getClassLoader();
            String policyURL = cl.getResource(policyFilePath).toString();
            
            System.setProperty("java.security.policy", policyURL);
            System.setSecurityManager(new SecurityManagerImpl());
        }
        
        splashProgress(11);        
        splashText("Preparing Tables...");
        
        JobTableModel localModel  = new JobTableModel();
        JobTableModel remoteModel = new JobTableModel();
        
        splashProgress(22);        
        splashText("Initializing MVC...");
        
        MainModel mainModel = new MainModel();
        MainView mainView   = new MainView(mainModel, localModel, remoteModel);
        MainController mainController = new MainController(mainView , mainModel);
        
        splashProgress(44);        
        splashText("Preparing Archive Manager...");
        
        ArchiveManager am = new ArchiveManager(//ArchiveStorage.getInstance(), 
                                               //ProgressManager.getInstance(),
                                               localModel, 
                                               remoteModel);
        
        splashProgress(55);        
        splashText("Starting Archive Manager...");
        
        am.start();
        
        splashProgress(66);        
        splashText("Preparing Extraction Queue Manager...");
        
        ExtractionQueueManager eqm = new ExtractionQueueManager(
                                            //ExtractionQueue.getInstance(), 
                                            new ThreadDispatcher(4));
        
        splashProgress(77);        
        splashText("Starting Extraction Queue Manager...");   
        
        eqm.start();
        
        splashProgress(88);        
        splashText("Registering Server...");
        boolean registerServerError = false;
        try {
            RemoteServer.registerServer();
        } catch (Exception ex) {
            Configuration config = Configuration.getInstance();
            boolean serverActive = config.getBoolean(Configuration.PROP.USER, "serverActive");
            registerServerError = (serverActive) ? true : false;
        }
        
        splashProgress(99);        
        splashText("Show User Interface...");        
        
        /*
        try {
            // TODO: Remove testing delay...
            Thread.sleep(5000);
        } catch (InterruptedException ex) {}
        //*/
        
        show(mainView);
        
        if (registerServerError) {
            mainView.setActiveServerControlsEnabled(false);
            mainView.showRegisterRemoteServerFailedMessage();
        }
    }

    /**
     * This method is to initialize the specified window by injecting resources.
     * Windows shown in our application come fully initialized from the GUI
     * builder, so this additional configuration is not needed.
     */
    @Override protected void configureWindow(java.awt.Window root) {
    }

    /**
     * A convenient static getter for the application instance.
     * @return the instance of JMoteExtractApp
     */
    public static JMoteExtractApp getApplication() {
        return Application.getInstance(JMoteExtractApp.class);
    }

    /**
     * Main method launching the application.
     */
    public static void main(String[] args) {
        launch(JMoteExtractApp.class, args);
    }
}
